﻿//  __  _  __    __   ___ __  ___ ___
// |  \| |/__\ /' _/ / _//__\| _ \ __|
// | | ' | \/ |`._`.| \_| \/ | v / _|
// |_|\__|\__/ |___/ \__/\__/|_|_\___|
// 
// Copyright (C) 2019 - NosCore
// 
// NosCore is a free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using NosCore.Core.Configuration;
using NosCore.Data.Enumerations.I18N;
using NosCore.Database;
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using NosCore.Core;
using NosCore.GameObject.InterChannelCommunication.Hubs.ChannelHub;
using NosCore.Networking;
using NosCore.Shared.I18N;
using Polly;

namespace NosCore.LoginServer
{
    public class LoginServer(IOptions<LoginConfiguration> loginConfiguration, NetworkManager networkManager,
            Serilog.ILogger logger, NosCoreContext context,
            ILogLanguageLocalizer<LogLanguageKey> logLanguage, Channel channel, IChannelHub channelHubClient)
        : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                Console.Title += $@" - Port : {Convert.ToInt32(loginConfiguration.Value.Port)}";
            }

            try
            {
                await context.Database.MigrateAsync(stoppingToken);
                await context.Database.GetDbConnection().OpenAsync(stoppingToken);
                logger.Information(logLanguage[LogLanguageKey.DATABASE_INITIALIZED]);
            }
            catch (Exception ex)
            {
                logger.Error(logLanguage[LogLanguageKey.DATABASE_ERROR], ex);
                logger.Error(logLanguage[LogLanguageKey.DATABASE_NOT_UPTODATE]);
                throw;
            }
            var connectTask = Policy
                 .Handle<Exception>()
                 .WaitAndRetryForeverAsync(retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                     (_, __, timeSpan) =>
                         logger.Error(
                             logLanguage[LogLanguageKey.MASTER_SERVER_RETRY],
                             timeSpan.TotalSeconds)
                 ).ExecuteAsync(() => channelHubClient.Bind(channel));

            await Task.WhenAny(connectTask, networkManager.RunServerAsync()).ConfigureAwait(false);
        }
    }
}